import axios from 'axios';
import { ElMessage } from 'element-plus';

// 存储token的名字
const authItemName = "access_token"

const accessHeader = () => {
    return {
        'Authorization': `Bearer ${takeAccessToken()}`
    }
}

// 默认失败信息 - 包装成统一的信息
const defaultFailure = (message, code, url) => {
    console.warn(`请求地址: ${url}, 状态码: ${code}, 错误信息: ${message}`)
    ElMessage.warning(message)
}

// 默认错误信息 - 直接控制台输出
const defaultError = (err) => {
    console.error(err)
    ElMessage.warning('发生未知错误，请联系管理员')
}

// 取出token
function takeAccessToken() {

    // 定义一个接收对象 - 从本地存储中 / 会话记录中找出
    const str = localStorage.getItem(authItemName) || sessionStorage.getItem(authItemName) || null

    // 判断是否存在
    if (!str){
        return null;
    }

    // 重新包装成一个对象，以便从里面取出信息
    const authObj = JSON.parse(str)

    // 判断过期时间
    if (authObj.expire <= new Date()) {
        // 调用删除token函数
        deleteAccessToken()
        ElMessage.warning('登录状态已过期，请重新登录')
        return null
    }
    
    // 如果通过上面的验证，就直接返回token
    return authObj.token
}

// 保存token函数 - token、是否记住状态、过期时间
function storeAccessToken(token, remember, expire) {

    // 定义一个对象
    const authObj = { token: token, expire: expire }
    // 把包裹了token和过期时间的对象进行JSON字符串转化
    const str = JSON.stringify(authObj)

    // 是否勾选了记住我
    if (remember)
        // 采用本地存储方式 - 关闭了还有
        localStorage.setItem(authItemName, str)
    else
        // 采用会话存储方式 - 关闭就没有了
        sessionStorage.setItem(authItemName, str)
}

// 删除token函数
function deleteAccessToken() {
    // 根据不同的方法，进行移除
    localStorage.removeItem(authItemName)
    sessionStorage.removeItem(authItemName)
}

// 内部使用的post和get请求
// 请求地址、数据、请求头、成功状态、失败状态、错误信息-回调函数
function internalPost(url, data, header, success, failure, error = defaultError) {

    // 发送请求
    // then是请求成功调用 - 解构data数据
    // catch是请求失败，捕获错误用的
    axios.post(url, data, { headers: header }).then(({ data }) => {

        // 判断状态码 - 以此来区别
        if (data.code === 200) {
            success(data.data)
        } else {
            // 失败就返回错误信息、错误代码、已经URL
            failure(data.message, data.code, url)
        }
    }).catch(err => error(err))
    // error是一个方法，继承了上面的defaultError
}

function internalGet(url, header, success, failure, error = defaultError) {

    // 从后端获取请求，不需要传输data数据
    axios.get(url, { headers: header }).then(({ data }) => {
        if (data.code === 200) {
            success(data.data)
        } else {
            failure(data.message, data.code, url)
        }
    }).catch(err => error(err))
}

// 向外暴露的get和post方法
function post(url, data, success, failure) {
    internalPost(url, data, accessHeader(), success, failure)
}

function get(url, success, failure = defaultFailure) {
    internalGet(url, accessHeader(), success, failure)
}


// 登录操作 - 传入用户名、密码、是否记住登录状态，后面是成功和失败的处理函数
function loginFn(username, password, remember, success, failure = defaultFailure) {

    // 使用内部函数进行请求
    internalPost('/api/auth/login', {
        // 这个是data数据信息
        username: username,
        password: password
    },{
        'Content-Type': 'application/x-www-form-urlencoded'
    },(data) => {
        // 成功的回调函数
        // 调用函数，储存token
        storeAccessToken(data.token, remember, data.expire)

        ElMessage.success(`登录成功`)
        success(data)
    }, failure)
}

// 退出登录
function logout(success, failure = defaultFailure) {
    get('/api/auth/logout', () => {

        // 调用函数，删除token信息
        deleteAccessToken()

        ElMessage.success('退出登录成功')
        success()
    }, failure)
}

// 状态过期
function expiredLogin(){
    // 清空本地存储
    deleteAccessToken()
    unauthorized()
}

// 判断是否登录了
function unauthorized() {
    return !takeAccessToken()
}

export {
    loginFn,
    logout,
    expiredLogin,
    get,
    post,
    unauthorized,
    takeAccessToken
}
